#include<assert.h>
#include<getopt.h>
#include<netdb.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/stat.h>
#include<unistd.h>

#include "server.h"
/* Description of long options for getopt_long.
 */
static const struct option long_options[] = { { "address", 1, NULL, 'a' }, {
		"help", 0, NULL, 'h' }, { "module-dir", 1, NULL, 'm' }, { "port", 1,
		NULL, 'p' }, { "verbose", 0, NULL, 'v' }, };

/* Description of short options for getopt_long.
 */
static const char* const short_options = "a:hm:p:v";

/* Usage summary text.*/
static const char* const usage_template = "Usage: %s [ options ]\n"
	" -a, --address ADDR Bind to local address (by default, bind\n"
	"to all local addresses).\n"
	"-h, --help Print this information.\n"
	"-m, --module-dir DIR Load modules from specified directory\n"
	"-p, --port PORT Bind to specified port.\n"
	"-v, --verbose Print verbose messages.\n";

/* Print usage information and exit. If IS_ERROR is nonzero, write to
 stderr and use an error exit code. Otherwise, write to stdout and
 use a non-error termination code. Does not return. */

static void print_usage(int is_error) {
	fprintf(is_error ? stderr : stdout, usage_template, program_name);
	exit(is_error ? 1 : 0);
}

int main(int argc, char* const argv[]) {
	struct in_addr local_address;
	uint16_t port;
	int next_option;
	/* Store the program name, which we'll use in error messages.*/
	program_name = argv[0];

	/* Set defaults for options. Bind the server to all local addresses,
	 and assign an unused port automatically. */
	local_address.s_addr = INADDR_ANY;
	port = 0;
	/* Don't print verbose messages. */
	verbose = 0;
	/* Load modules from the directory containing this executable. */
	module_dir = get_self_executable_directory();
	assert(module_dir != NULL);
	/* Parse options. */
	do {
		next_option
				= getopt_long(argc, argv, short_options, long_options, NULL);
		switch (next_option) {
		case 'a':
			/* User specified -a or --address. */
		{
			struct hostent* local_host_name;
			/* Look up the hostname the user specified. */
			local_host_name = gethostbyname(optarg);
			if (local_host_name == NULL || local_host_name->h_length == 0)
				/* Could not resolve the name. */
				error(optarg, "invalid host name");
			else
				/* Hostname is OK, so use it. */
				local_address.s_addr
						= *((int*) (local_host_name->h_addr_list[0]));
		}
			break;
		case 'h':
			/* User specified -h or --help.*/
			print_usage(0);

		case 'm':
			/* User specified -m or --module-dir.*/
		{
			struct stat dir_info;

			/* Check that it exists. */
			if (access(optarg, F_OK) != 0)
				error(optarg, "module directory does not exist");
			/* Check that it is accessible. */
			if (access(optarg, R_OK | X_OK) != 0)
				error(optarg, "module directory is not accessible");
			/* Make sure that it is a directory. */
			if (stat(optarg, &dir_info) != 0 || !S_ISDIR(dir_info.st_mode))
				error(optarg, "not a directory");
			/* It looks OK, so use it. */
			module_dir = strdup(optarg);
		}
			break;
		case 'p':
			/* User specified -p or --port.*/
		{
			long value;
			char* end;

			value = strtol(optarg, &end, 10);
			if (*end != '\0')
				/* The user specified nondigits in the port number. */
				print_usage(1);
			/* The port number needs to be converted to network (big endian)
			 byte order. */
			port = (uint16_t) htons(value);
		}
			break;
		case 'v':
			/* User specified -v or --verbose.*/
			verbose = 1;
			break;
		case '?':
			/* User specified an unrecognized option.*/
			print_usage(1);
		case -1:
			/* Done with options.*/
			 break;


		default:
			abort();
		}
	} while (next_option != -1);

	/* This program takes no additional arguments.
	 user specified any. */
	if (optind != argc)
		print_usage(1);
	//Issue an error if the
	/* Print the module directory, if we're running verbose. */
	if (verbose)
	printf ("modules will be loaded from %s\n", module_dir);
	/* Run the server. */
	server_run(local_address, port);
	return 0;
}

